#include "FunctionGraph.h"
#include "base/Utility.h"
#include "base/TrueTypeFont.h"
#include "MainWindow.h"
#include "GraphContainer.h"
#include "InputPin.h"
#include "OutputPin.h"
#include "InputParaPin.h"
#include "OutputParaPin.h"

#define SetAttr(AttrName) SetAttribute(AttrName, ele->Attribute(AttrName));
bool FunctionGraph::OnInit()
{
    GraphBase* nextG = context.FindGraphById(nextGraphId);
    if (nextG != nullptr)
    {
        nextGraph = nextG;
    }
    else {
        printf("FunctionGraph not find nextGraph:%d\r\n", nextGraphId);
    }
    return false;
}
void FunctionGraph::InitParaPin()
{
    FunctionPin* fp = dynamic_cast<FunctionPin*>(pin);
    if (fp != nullptr)
    {
        while (opp.size() < fp->GetOutputResultNum())
        {
            OutputParaPin* ouP = NewObj<OutputParaPin>();
            ouP->gbParent = this;
            // ouP->parent = this;
            ouP->indexInFunc = opp.size();
            opp.push_back(ouP);
        }
        while (ipp.size() < fp->GetInputParameterNum())
        {
            InputParaPin* inP = NewObj<InputParaPin>();
            inP->gbParent = this;
            // ouP->parent = this;
            inP->indexInFunc = ipp.size();
            ipp.push_back(inP);
        }
    }
}
void FunctionGraph::LoadXmlElement(TiXmlElement* ele)
{
    return;
    TiXmlNode* tn = ele->FirstChild();
    TiXmlElement* fc = tn->ToElement();
    while (fc != nullptr)
    {
        if (strcmp(fc->Value(), "Body") == 0)
        {
            TiXmlNode* n_graphnode = fc->FirstChild();
            TiXmlElement* ele_graph = n_graphnode->ToElement();
            while (ele_graph)
            {
                GraphBase* gb = CreateGraph(ele_graph->Value());
                if (gb)
                {
                    gb->ParseXmlElement(ele_graph);
                }
                allNodes.push_back(gb);
                ele_graph = ele_graph->NextSiblingElement();
            }
        }
        fc = fc->NextSiblingElement();
    }
    for (int i = 0;i < allNodes.size();i++)
    {
        allNodes[i]->context.allGraph = &allNodes;
        allNodes[i]->OnInit();
    }
    MainWindow* mwin = dynamic_cast<MainWindow*>(this->rootWindow);
    Control* ctrl = mwin->GetControlById("gContainer");
    if (ctrl != nullptr)
    {
        GraphContainer* container = dynamic_cast<GraphContainer*>(ctrl);
        // container->context.allGraph = context.allGraph;
        std::vector<GraphBase*>* caGraph = context.allGraph = &allNodes;
        for (int i = 0;i < allNodes.size();i++) {
            allNodes[i]->containerParent = this->containerParent;
            container->childs.push_back(std::make_pair((*caGraph)[i]->graphName.val, allNodes[i]));
        }
    }
}
void FunctionGraph::ParseXmlElement(TiXmlElement* ele)
{
    SetAttr("id")
        SetAttr("func")
        SetAttr("pos")
        SetAttr("size")
        SetAttr("onNext")
}

GraphBase* FunctionGraph::CreateGraph(std::string sControlClassName)
{
    GraphBase* ctrl = dynamic_cast<GraphBase*>(BlueprintScriptLibrary::BlueprintDataPool::GetInstance()->createInstFuncs[sControlClassName]());
    ctrl->rootWindow = rootWindow;
    return ctrl;
}
GraphBase* FunctionGraph::FindGraphById(int id)
{
    for (int i = 0;i < allNodes.size();i++)
    {
        if (allNodes[i]->id.val == id)
        {
            return allNodes[i];
        }
    }
    return nullptr;
}
bool FunctionGraph::SetAttribute(const char* attrName, const char* attrVal)
{

    if (strcmp("id", attrName) == 0)
    {
        graphId.val = atoi(attrVal);
    }
    else if (strcmp("func", attrName) == 0)
    {
        //fp = GetFunctionPin(attrVal);
        graphName = attrVal;
    }
    else if (strcmp("name", attrName) == 0)
    {
        graphName = attrVal;
    }
    else if (strcmp("pos", attrName) == 0)
    {
        int posX, posY;
        sscanf_s(attrVal, "%d,%d", &posX, &posY);
        pos.x.val = posX;
        pos.y.val = posY;
    }
    else if (strcmp("size", attrName) == 0)
    {
        int x, y;
        sscanf_s(attrVal, "%d,%d", &x, &y);
        size.x.val = x;
        size.y.val = y;
    }
    else if (strcmp("onNext", attrName) == 0)
    {
        nextGraphId = atoi(attrVal);
    }

    return false;
}

void FunctionGraph::OnDraw()
{
    if (ip == nullptr)
    {
        ip = NewObj<InputPin>();
        ip->gbParent = this;
    }
    if (op == nullptr)
    {
        op = NewObj<OutputPin>();
        op->gbParent = this;

    }
    glLineWidth(1);
    glColor3f(1, 1, 1);
    glPushMatrix();
    glTranslatef(baseOffset.x.val, baseOffset.y.val,0.f);
    if (bFocused)
    {
        glEnable(GL_FILL);
        glColor3f(0.2, 0.2, 0.2);
        glBegin(GL_QUADS);

    }
    else
    {
        glDisable(GL_FILL);
        glBegin(GL_LINE_LOOP);
    }

    glVertex3f(pos.x.val, pos.y.val, zIndex.val);
    glVertex3f(pos.x.val + size.x.val, pos.y.val, zIndex.val);
    glVertex3f(pos.x.val + size.x.val, pos.y.val + size.y.val, zIndex.val);
    glVertex3f(pos.x.val, pos.y.val + size.y.val, zIndex.val);
    glEnd();
    glColor3f(1, 1, 1);
    std::wstring wstr = Utility::ConvertToWstring(graphName.val);
    wchar_t* str = const_cast<wchar_t*>(wstr.data());
    TrueTypeFont::GetInst()->drawText(str, pos.x.val + size.x.val / 4, pos.y.val + 50, zIndex.val, size.x.val, 20);


    FunctionPin* fp = dynamic_cast<FunctionPin*>(pin);
    if (fp == nullptr)
    {
        printf("fp is nullptr!");
    }
    else {
        if (op->p == nullptr)
            op->p = &fp->next;

        glPointSize(9);
        int outNum = fp->GetOutputResultNum();
        int inNum = fp->GetInputParameterNum();


        for (int i = 0;i < outNum;i++)
        {
            opp[i]->pos.x = pos.x.val + size.x.val - 10;
            opp[i]->pos.y = pos.y.val + i * 6 + (i + 1) * size.y.val / (outNum + 1);
            opp[i]->Draw();
        }
        for (int i = 0;i < inNum;i++)
        {
            ipp[i]->pos.x = pos.x.val + 10;
            ipp[i]->pos.y = pos.y.val + i * 6 + (i + 1) * size.y.val / (inNum + 1);
            ipp[i]->Draw();
            // glVertex3f(pos.x.val + 10, pos.y.val + i * 6 + (i + 1) * size.y.val / (inNum + 1), 0);
        }

    }
    ip->pos.x.val = pos.x.val + 20;
    ip->pos.y.val = pos.y.val + 15;
    ip->Draw();

    op->pos.x = pos.x.val + size.x.val - 20;
    op->pos.y = pos.y.val + 15;
    op->Draw();
    glPopMatrix();
    //input
    //glColor3f(1, 1, 1);
    //glBegin(GL_LINE_LOOP);
    //// -6,-4 6,4 18,0
    //glVertex3f(pos.x.val +  20 - 6, pos.y.val + 15 - 4, 0);
    //glVertex3f(pos.x.val +  20 + 6, pos.y.val + 15 - 4, 0);
    //glVertex3f(pos.x.val +  20 + 18, pos.y.val + 15, 0);
    //glVertex3f(pos.x.val +  20 + 6, pos.y.val + 15 + 4, 0);
    //glVertex3f(pos.x.val + 20 - 6, pos.y.val + 15 + 4, 0);
    //glEnd();

    //glColor3f(1, 1, 1);
    //glBegin(GL_LINE_LOOP);
    //// -6,-4 6,4 18,0
    //glVertex3f(pos.x.val + size.x.val - 20 - 6, pos.y.val + 15 - 4, 0);
    //glVertex3f(pos.x.val + size.x.val - 20 + 6, pos.y.val + 15 - 4, 0);
    //glVertex3f(pos.x.val + size.x.val - 20 + 18, pos.y.val + 15, 0);
    //glVertex3f(pos.x.val + size.x.val - 20 + 6, pos.y.val + 15 + 4, 0);
    //glVertex3f(pos.x.val + size.x.val - 20 - 6, pos.y.val + 15 + 4, 0);
    //glEnd();
    //glPopMatrix();
}

void FunctionGraph::onMouseButtonDown(int button, int x, int y)
{
    __super::onMouseButtonDown(button, x, y);
    if (op != nullptr)
    {
        Vec2vbi point;
        point.x.val = x;
        point.y.val = y;
        if (op->HitTest(vec2(point.x.val,point.y.val)))
        {
            op->onMouseButtonDown(button, x, y);
        }
    }
    if (ipp.size() > 0)
    {
        for (int i = 0;i < ipp.size();i++)
        {
            Vec2vbi point;
            point.x.val = x;
            point.y.val = y;
            if (ipp[i]->HitTest(vec2(point.x.val, point.y.val)))
            {
                ipp[i]->onMouseButtonDown(button, x, y);
            }
        }
    }
    if (opp.size() > 0)
    {
        for (int i = 0;i < opp.size();i++)
        {
            Vec2vbi point;
            point.x.val = x;
            point.y.val = y;
            if (opp[i]->HitTest(vec2(point.x.val, point.y.val)))
            {
                opp[i]->onMouseButtonDown(button, x, y);
            }
        }
    }
}

void FunctionGraph::onMouseMove(int x, int y)
{
    __super::onMouseMove(x, y);
}

void FunctionGraph::onMouseButtonUp(int button, int x, int y)
{
    __super::onMouseButtonUp(button, x, y);
    if (ip != nullptr)
    {
        Vec2vbi point;
        point.x.val = x;
        point.y.val = y;
        if (ip->HitTest(vec2(point.x.val,point.y.val)))
        {
            ip->onMouseButtonUp(button, x, y);
        }
    }
    if (ipp.size() > 0)
    {
        for (int i = 0;i < ipp.size();i++)
        {
            Vec2vbi point;
            point.x.val = x;
            point.y.val = y;
            if (ipp[i]->HitTest(vec2(point.x.val, point.y.val)))
            {
                ipp[i]->onMouseButtonUp(button, x, y);
            }
        }
    }
    if (opp.size() > 0)
    {
        for (int i = 0;i < opp.size();i++)
        {
            Vec2vbi point;
            point.x.val = x;
            point.y.val = y;
            if (opp[i]->HitTest(vec2(point.x.val, point.y.val)))
            {
                opp[i]->onMouseButtonUp(button, x, y);
            }
        }
    }
}

BlueprintScriptLibrary::Class* FunctionGraph::GetClass()
{
    return nullptr;
}

Vec2vbi FunctionGraph::GetOutputPinPos(int index)
{
    return Vec2vbi();
}

VarBaseInt FunctionGraph::GetInputParaNum()
{
    FunctionPin* fp = dynamic_cast<FunctionPin*>(pin);
    if (fp == nullptr)
    {
        printf("fp is nullptr!");
        return 0;
    }
    return  fp->GetInputParameterNum();
}

VarBaseInt FunctionGraph::GetOuputResultNum()
{
    FunctionPin* fp = dynamic_cast<FunctionPin*>(pin);
    if (fp == nullptr)
    {
        printf("fp is nullptr!");
        return 0;
    }
    return  fp->GetOutputResultNum();
}

void FunctionGraph::Execute()
{
    FunctionPin* fp = dynamic_cast<FunctionPin*>(pin);
    if (fp)
    {
        //fp->Execute();
        SolvePin(fp);
    }
    else {
        allNodes[0]->Execute();
    }
}

FunctionPin* FunctionGraph::GetFunctionPin(std::string funcName)
{
    auto& funcs = BlueprintScriptLibrary::BlueprintDataPool::GetInstance()->allFunctionObjs;
    for (int i = 0;i < funcs.size();i++)
    {
        if (funcs[i]->GetName() == funcName)
        {
            return funcs[i];
        }
    }
    return nullptr;
}

void FunctionGraph::ConnectTo(GraphBase* graph, int index)
{
    if (GetOuputPinNum().val > index || graph == nullptr) return;
    if (graph->GetInputPinNum().val > 0)
    {
        nextGraph = graph;
    }
}
